package com.shy.base.component;

import java.sql.SQLException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.authc.AuthenticationException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import com.shy.base.util.Result;

/**
 * Controller advice to translate the server side exceptions to client-friendly json structures.
 */
@ControllerAdvice
public class ExceptionTranslator {

	/**
     * log
     */
	private Logger logger = LogManager.getLogger(this.getClass());

    /**
     * 异常信息处理，用于valid检验有问题返回到客户端
     * 
     * @param ex
     *            异常
     * @return
     * @author shanhanyu
     * @date 2018/2/6
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public Result processValidationError(MethodArgumentNotValidException ex) {
        logger.error(ex.getMessage());
        BindingResult result = ex.getBindingResult();
        FieldError error = result.getFieldError();
        return getFieldErrorResult(error);
    }

    /**
     * 异常信息处理，用于valid检验有问题返回到客户端
     * 
     * @param ex
     *            异常
     * @return
     * @author shanhanyu
     * @date 2018/2/6
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public Result processException(BindException ex) {
        logger.error(ex.getMessage());
        FieldError error = ex.getFieldError();
        return getFieldErrorResult(error);
    }

    /**
     * 对hibernate-validator异常错误信息简单处理
     * 
     * @param error
     *            字段错误信息
     * @return
     */
    private Result getFieldErrorResult(FieldError error) {
        StringBuilder errorMsg = new StringBuilder(100);
        errorMsg.append("current obj field [ ");
        errorMsg.append(error.getField());
        errorMsg.append(" ]  not valid ,");
        errorMsg.append(error.getDefaultMessage());
        Result _result = new Result();
        _result.setMessage(errorMsg.toString());
        _result.setCode("field valid");
        return _result;
    }
    
    /**
     * SQL异常捕獲
     * @param ex
     * @return
     * @author shanhanyu
     * @date 2018/10/5
     */
    @ExceptionHandler(SQLException.class)
    @ResponseBody
    public Result sqlExceptionHandler(SQLException e){
        logger.error(e.getMessage());
        Result result = new Result();
        result.setError("[error:" + e.getMessage() + ",stackTrace:" + getExceptionTrace(e) + "]");
        result.setMessage("[SQL异常]");
        result.setCode("db");
        return result;
    }
    
    
    /**
     * 权限验证失败
     * @param ex
     * @return
     * @author shanhanyu
     * @date 2018/10/11
     */
    @ExceptionHandler(AuthenticationException.class)
    @ResponseBody
    public Result processException(AuthenticationException e) {
        logger.error(e.getMessage());
        Result result = new Result();
        result.setMessage("无权限访问");
        result.setCode("auth");
        return result;
    }
    

    /**
     * 普通的异常交给 {@link ExceptionResolver} 处理 兼容 页面 异常和ajax异常
     */
     @ExceptionHandler(Exception.class)
     @ResponseBody
     public Result processException(Exception e) {
         logger.error("[ runtime error :" + e + "]");
         Result result = new Result();
         result.setError("[error:" + e.getMessage() + ",stackTrace:" + getExceptionTrace(e) + "]");
         result.setMessage("[" + convertException(e) + "]");
         result.setCode("runtime");
         return result;
     }
     
     /**
      * 处理系统异常信息，客户端友好提示
      * @param exception
      * @return
      * @author shanhanyu
      * @date 2018/10/16
      */
     private String convertException(Exception exception){
         if(exception.toString().indexOf("NullPointer") != -1) return "信息为空异常，请检查数据完整性";
         if(exception.toString().indexOf("IndexOutOfBoundsException") != -1) return "数组越界异常，请检查是否数据行列或者模板是否正确";
         if(exception.toString().indexOf("NumberFormatException") != -1) return "数字转换异常，请检查是否数据中的数字格式";
         if(exception.toString().indexOf("java.text.ParseException") != -1) return "格式转换异常，请检查是否数据中的日期等数据格式";
         if(exception.toString().indexOf("TemplateNotFoundException") != -1) return "模板文件不存在，请检查目录下是否存在对应模板";
         if(exception.toString().indexOf("TemplateException") != -1) return "模板标签有误，请核对";
         return "系统异常";
     }
     
     
     /**
      * 獲取异常產生的文件和行號
      * @param exception
      * @return
      * @author shanhanyu
      * @date 2018/10/19
      */
     private String getExceptionTrace(Exception exception){
         String stackTrace = "";
         for(StackTraceElement st : exception.getStackTrace()){
             if(st.getClassName().indexOf("com.shy") != -1){
                 stackTrace += "[文件/類：" + st.getFileName() + "，方法：" + st.getMethodName() + "，行數：" + st.getLineNumber() +"];";
             }
         }
         logger.error(stackTrace);
         return stackTrace;
     }
     
}
